﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TestGame {
    /// <summary>
    /// A popup confirmation box screen, that is used to display a message,
    /// and ask for the user's confirmation on it. If the user confirms it,
    /// the Screen then calls the Accepted event handlers and exits. If the 
    /// user declines it, it calls the Cancelled event handlers and exits.
    /// </summary>
    class ConfirmMessageBoxScreen : GameScreen {
        #region Fields

        string message;
        Texture2D gradientTexture;

        bool selectedEntry;
        MenuEntry yesEntry;
        MenuEntry noEntry;

        string newLineString;

        #endregion

        #region Events

        public event EventHandler<PlayerIndexEventArgs> Accepted;
        public event EventHandler<PlayerIndexEventArgs> Cancelled;

        #endregion

        #region Initialization

        /// <summary>
        /// Constructs a confirmation screen with the given message.
        /// </summary>
        public ConfirmMessageBoxScreen(string message) {
            this.message = message;

            newLineString = "";
            yesEntry = new MenuEntry("Yes");
            noEntry = new MenuEntry("No");

            foreach (char character in message.ToCharArray()) {
                if (character == '\n') {
                    newLineString = '\n' + newLineString;
                }
            }

            selectedEntry = false;
            IsPopup = true;

            TransitionOnTime = TimeSpan.FromSeconds(0.2);
            TransitionOffTime = TimeSpan.FromSeconds(0.2);
        }


        /// <summary>
        /// Loads graphics content for this screen. This uses the shared ContentManager
        /// provided by the Game class, so the content will remain loaded forever.
        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
        /// it will just get backEntry another reference to the already loaded data.
        /// </summary>
        public override void LoadContent() {
            ContentManager content = ScreenManager.Game.Content;

            gradientTexture = content.Load<Texture2D>("gradient");
        }


        #endregion

        #region Handle Input

        /// <summary>
        /// Responds to user input, by changing, accepting, or cancelling the confirmation box.
        /// </summary>
        public override void HandleInput(InputState input) {
            PlayerIndex playerIndex;

            /* Upon a menu being selected, we either accept or cancel depending 
             * on the user's choice, which is determined by selectedEntry */
            if (input.IsMenuSelect(ControllingPlayer, out playerIndex)) {
                if (selectedEntry) {
                    if (Accepted != null) {
                        Accepted(this, new PlayerIndexEventArgs(playerIndex));
                    }
                }
                else {
                    if (Cancelled != null) {
                        Cancelled(this, new PlayerIndexEventArgs(playerIndex));
                    }
                }

                // Exit regardless of choice made
                ExitScreen();
            }
            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex)) {
                // If the menu was cancelled, just flag cancel and exit the screen
                if (Cancelled != null) {
                    Cancelled(this, new PlayerIndexEventArgs(playerIndex));
                }

                ExitScreen();
            }
            else if (input.IsRightButtonPressed()) {
                // If the right button is pressed, the No option is selected, as it is on the right.
                selectedEntry = false;
            }
            else if (input.IsLeftButtonPressed()) {
                // If the left button is pressed, the Yes option is selected, as it is on the left.
                selectedEntry = true;
            }
        }

        #endregion

        #region Update Method

        /// <summary>
        /// Updates the confirm box, which is needed for the two menu entries contained inside it.
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="otherScreenHasFocus"></param>
        /// <param name="coveredByOtherScreen"></param>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            yesEntry.Update(this, selectedEntry, gameTime);
            noEntry.Update(this, !selectedEntry, gameTime);
        }

        #endregion

        #region Draw

        /// <summary>
        /// Draws the message box.
        /// </summary>
        public override void Draw(GameTime gameTime) {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;

            // Darken down any other screens that were drawn beneath the popup.
            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);

            // The background includes a border somewhat larger than the text itself.
            const int hPad = 32;
            const int vPad = 16;

            // Center the message text in the viewport.
            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
            Vector2 textSize = font.MeasureString(message + '\n');
            Vector2 textPosition = (viewportSize - textSize) / 2;
            Vector2 yesPosition = textPosition + font.MeasureString(newLineString) + new Vector2(0, vPad);
            Vector2 noPosition = yesPosition + new Vector2(font.MeasureString("Yes").X * 2, 0);

            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
                                                          (int)textPosition.Y - vPad,
                                                          (int)textSize.X + hPad * 2,
                                                          (int)textSize.Y + vPad * 2);

            // Fade the popup alpha during transitions.
            Color color = Color.White * TransitionAlpha;

            spriteBatch.Begin();

            // Draw the background rectangle.
            spriteBatch.Draw(gradientTexture, backgroundRectangle, color);

            // Set the positions for the Yes and No Entries
            yesEntry.Position = yesPosition;
            noEntry.Position = noPosition;

            // Draw the two Menu Entries for yes and no
            yesEntry.Draw(this, selectedEntry, gameTime);
            noEntry.Draw(this, !selectedEntry, gameTime);

            // Draw the message box text.
            spriteBatch.DrawString(font, message, textPosition, color);

            spriteBatch.End();
        }


        #endregion
    }
}
